package com.blue.http.websocket;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * Websocket路由，绑定帐号和链路的关系
 * 
 * @author zhengj
 * @since 1.0 2016年12月15日
 */
public class WebsocketRouter
{
	// Map<url, ChannelGroup>
	private Map<String, ChannelGroup> brodercast = new ConcurrentHashMap<>();
	

	// Map<channelId, Channel>
	private Map<String, Channel> chMap = new ConcurrentHashMap<>();
	// Map<url, Map<accountId, channelId>>
	private Map<String, Map<String, Set<String>>> urlEmMap = new ConcurrentHashMap<>();
	// Map<url, Map<channelId, accountId>>
	private Map<String, Map<String, String>> urlChMap = new ConcurrentHashMap<>();
	
	public WebsocketRouter()
	{
	}
	
	public void addBrodercast(String url, Channel ch)
	{
//		String id = ch.id().asLongText();
//		chMap.put(id, ch);
		ChannelGroup cg = brodercast.computeIfAbsent(url, (k) -> new DefaultChannelGroup(GlobalEventExecutor.INSTANCE));
		cg.add(ch);
	}
	
	public ChannelGroup listBrodercast(String url)
	{
		return brodercast.get(url);
	}
	
	public void addPoint(String url, String accountId, Channel ch)
	{
		String id = ch.id().asLongText();
		chMap.put(id, ch);
		
		Map<String, String> cMap = urlChMap.computeIfAbsent(url, (u) -> new ConcurrentHashMap<>());
		cMap.put(id, accountId);
		
		Map<String, Set<String>> eMap = urlEmMap.computeIfAbsent(url, (u) -> new ConcurrentHashMap<>());
		Set<String> eSet = eMap.computeIfAbsent(accountId, (e) -> ConcurrentHashMap.newKeySet());
		eSet.add(id);
	}
	
	public void deletePoint(Channel ch)
	{
		String id = ch.id().asLongText();
		chMap.remove(id);
		for (Map.Entry<String, Map<String, String>> c : urlChMap.entrySet())
		{
			if (c.getValue() != null)
			{
				Map<String, String> cMap = c.getValue();
				String accountId = cMap.get(id);
				cMap.remove(id);
				if (accountId != null)
				{
					for (Map.Entry<String, Map<String, Set<String>>> e : urlEmMap.entrySet())
					{
						if (e.getValue() != null)
						{
							Map<String, Set<String>> eMap = e.getValue();
							Set<String> chIdSet = eMap.get(accountId);
							if (chIdSet != null)
							{
								chIdSet.remove(id);
								if (chIdSet.isEmpty())
								{
									eMap.remove(accountId);
								}
							}
						}
					}
				}
			}
		}
	}
	
	public List<Channel> listPoint(String url, String accountId)
	{
		List<Channel> chList = new ArrayList<>();
		Map<String, Set<String>> cMap = urlEmMap.get(url);
		if (cMap == null || cMap.isEmpty())
			return chList;
		
		Set<String> cSet = cMap.get(accountId);
		if (cSet == null || cSet.isEmpty())
			return chList;
		
		for (String c : cSet)
		{
			Channel ch = chMap.get(c);
			if (ch != null)
			{
				chList.add(ch);
			}
		}
		return chList;
	}
	
}
